package com.hznu.stmanage.credentials;

import com.hznu.stmanage.entity.Manager;
import com.hznu.stmanage.entity.Student;
import com.hznu.stmanage.entity.Teacher;
import com.hznu.stmanage.utils.Util;
import com.hznu.stmanage.utils.cryptolib.CryptoApp;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>User: Zhang Kaitao
 * <p>Date: 14-1-28
 * <p>Version: 1.0
 *  限制登录次数，如果5次出错，锁定10分钟
 */
//HashedCredentialsMatcher 在Shiro教程P47，重试次数P49
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {


    private Cache<String, AtomicInteger> passwordRetryCache;

    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
        /**
         * 创建ehcache缓存，创建之后的有效期是10分钟；在ehcahe.xml中配置
         */
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }

    /**
     * 密码验证
     * @param token 登陆的用户信息
     * @param info 数据库里面的用户信息
     * @return
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        boolean matches=false;
        try {
            //info 来自UserRealm类doGetAuthenticationInfo方法的返回值

            String username = (String) token.getPrincipal();
            //retry count + 1
            AtomicInteger retryCount = passwordRetryCache.get(username);
            if (retryCount == null) {
                retryCount = new AtomicInteger(0);
                passwordRetryCache.put(username, retryCount);
            }
            if (retryCount.incrementAndGet() > 5) {
                //if retry count > 5 throw
                throw new ExcessiveAttemptsException();
            }

            //shiro密码验证
            //matches = super.doCredentialsMatch(token, info);

            //自定义密码验证
            //UsernamePasswordToken封装登录用户名及密码
            UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
            String salt="";
            Object object = Util.threadLocal.get();

            if(NumberUtils.isDigits(usernamePasswordToken.getUsername())){//登录名为纯数字
                if(Student.class.isInstance(object)){
                    Student student = (Student) object;
                    salt = student.getSalt();
                }
                else if(Teacher.class.isInstance(object)){
                    Teacher teacher = (Teacher) object;
                    salt = teacher.getSalt();
                }
            }
            else{
                Manager manager = (Manager) object;
                salt = manager.getSalt();
            }

            //将token中的原始密码进加密
            Object tokenCredentials = CryptoApp.PwdTransValue(String.valueOf(usernamePasswordToken.getPassword()).getBytes(), Util.hexStringToBytes(salt));

            //获取db中的用户密码
            Object accountCredentials = getCredentials(info);

            //将原始密码加密与取自DB的用户密码校验，内容一致就返回true,不一致就返回false
            matches = equals(tokenCredentials, accountCredentials);

            if (matches) {
                //clear retry count
                passwordRetryCache.remove(username);
            }
        }catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
        return matches;
    }
}
